package main

import (
	"bufio"
	"io"
	"log"
	"os/exec"
	"strings"
	"sync"
	"syscall"
	"time"
)

// NetstatLine 表示 netstat 的输出结果的一行.
type NetstatLine struct {
	Seq            int
	Proto          string
	Recv           int
	Send           int
	LocalAddress   string
	ForeignAddress string
	State          string
	PidProgram     string
	RES            string
	PCPU           string
	ProgramName    string
	CurrentSession bool
}

// ParseNetstatLines 解析 netstat -atnp 输出结果.
func ParseNetstatLines(lines []string, clientAddr string) (netstatLines []NetstatLine) {
	parsingStarted := false

	for _, line := range lines {
		if parsingStarted {
			l := parseLine(line)
			if !strings.HasPrefix(l.Proto, "tcp") {
				break
			}
			l.Seq = len(netstatLines) + 1
			l.CurrentSession = l.LocalAddress == clientAddr || l.ForeignAddress == clientAddr
			netstatLines = append(netstatLines, l)
			continue
		}

		if strings.Contains(line, "Proto") {
			parsingStarted = true
		}
	}

	return
}

// ExecuteShell executes shell scripts on host.
//func ExecuteShell(shellScripts string, timeout time.Duration) ([]string, error) {
//	log.Printf("exec %s", shellScripts)
func RunProgramName(shell string, timeout time.Duration) ([]string, error) {
	log.Printf("exec %s", shell)

	// Exec script with parameter...
	cmd := exec.Command("sh", "-c", shell)

	// Combine cmd stdout and stderr
	outReader, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	errReader, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}
	cmdReader := io.MultiReader(outReader, errReader)

	// Start the script...
	if err := cmd.Start(); err != nil {
		return nil, err
	}

	var lines []string
	// Create wait group to wait for command output completion
	var wg sync.WaitGroup

	wg.Add(1)

	// Write script output to log file and the work message channel
	go func(reader io.Reader) {
		defer wg.Done()

		scanner := bufio.NewScanner(reader)
		for scanner.Scan() {
			line := scanner.Text()
			lines = append(lines, line)
		}
		if err := scanner.Err(); err != nil {
			log.Printf("read err: %v", err)
		}

	}(cmdReader)

	// Start timeout timer
	timer := time.AfterFunc(timeout, func() {
		log.Printf("htimed out, killing process %d ...", cmd.Process.Pid)
		syscall.Kill(cmd.Process.Pid, syscall.SIGKILL)
	})

	// Wait for command output completion
	wg.Wait()

	// Wait for command completion
	err = cmd.Wait()

	// Stop timeout timer
	timer.Stop()

	// Mark work as terminated
	return lines, nil
}
